import com.environment.Aim;
import com.environment.Bot;
import com.environment.Order;
import com.environment.Percept;
import com.environment.Tile;
import com.knowledge.facts.EnemyHillFact;
import com.knowledge.facts.Fact;
import com.knowledge.facts.FactRepository;
import com.knowledge.facts.FriendlyAntFact;
import com.knowledge.facts.paths.AttackHillPathFact;
import com.knowledge.facts.paths.PathFact;
import com.knowledge.goals.FewerEnemys;
import com.knowledge.goals.Goal;
import com.knowledge.goals.MoreFriends;
import com.knowledge.plans.GoalPlan;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/**
 * Starter bot implementation.
 */
public class MyBot extends Bot {
    private Set<Goal> agenda = new HashSet<Goal>();
    MyBot() {
        agenda.add(new FewerEnemys());
        agenda.add(new MoreFriends());
    }
    /**
     * Main method executed by the game engine for starting the bot.
     * 
     * @param args command line arguments
     * 
     * @throws IOException if an I/O error occurs
     */
    public static void main(String[] args) throws IOException {
        new MyBot().readSystemInput();
    }
        
    /**
     * For every ant check every direction in fixed order (N, E, S, W) and move it if the tile is
     * passable.
     */

    @Override
    public void doTurn() {        
        
        for (Goal goal: agenda) {
            goal.deliberate();
        }
        
        Map<FriendlyAntFact,PathFact> optimalMoves = new HashMap<FriendlyAntFact,PathFact>();
        
        for (Fact fact: Percept.getInstance().getMyAnts()) {
            FriendlyAntFact ant = (FriendlyAntFact) fact;
            for (Fact pathFact: ant.getAllReferences()) {
                PathFact path = (PathFact) pathFact;
                if (path.getRemainingSteps() > 0) {
                    // if an ant doesn't have any best move selected, select this one
                    if (!optimalMoves.containsKey(ant)) optimalMoves.put(ant, path);
                    // otherwise it does, so select this one if its utility is higher
                    else if (path.getUtility() > optimalMoves.get(ant).getUtility()) optimalMoves.put(ant, path);
                } else {
                    if (path instanceof AttackHillPathFact) {
                        // we don't remove hills once we've seen them
                        // so this code removes hills.
                        FactRepository.getInstance().removeInstance(new EnemyHillFact(path.getLocation()));
                    }
//                    System.err.println("Path with no moves");
//                    System.err.println(" "+path.getName());
                    FactRepository.getInstance().removeInstance(path);                    
                }
            }
        }
        
        Set<Order> orders = new HashSet<Order>();
        
        for (PathFact path: optimalMoves.values()) {
//            System.err.println(path.getName());
            
            Order order = new Order(path.getSource(), path.getNextAim());
            // suicide is bad, so prevent it.
            if (!orders.contains(order)) {
                System.out.println(order);
                orders.add(order);
                path.updateSource();
            } 
        }
        
//        FactRepository.getInstance().printSize();
    }
}

